package com.tianquan.miracle.util;/**
 * @author starsea
 * @date 2024-09-30 上午9:08
 */

import com.tianquan.miracle.context.ApplicationContext;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @BelongsProject: uploaddemo
 * @BelongsPackage: com.tianquan.miracle.util
 * @Author: tianquan
 * @CreateTime: 2024-09-30  09:08
 * @Description: spi实现
 * @Version: 1.0
 */

public class ServiceClassLoader {

    private static ApplicationContext applicationContext;

    public static void init(ApplicationContext applicationContext) {
        ServiceClassLoader.applicationContext = applicationContext;
    }

    private static final String CLASSPATH = "META-INF/miracle";

    /**
     * @description: 获取META-INF/miracle文件夹
     * @author: tianquan
     * @date: 2024/10/17 下午9:23
     * @param: []
     * @return: java.io.File
     **/
    private static File getResourcesFile() {
        return new File(ClassLoader.getSystemClassLoader().getResource(CLASSPATH).getFile());
    }

    /**
     * @description: 根据接口的class获取META-INF/miracle下对应的实现类,并且实例化到容器中
     * @author: tianquan
     * @date: 2024/10/14 下午7:25
     * @param: [clazz]
     * @return: java.util.List<T>
     **/
    public static <T> List<T> Loader(Class<T> clazz) {
        List<T> list = null;
        String interfaceName = clazz.getCanonicalName();
        // 基于io流获取Resource下的META-INF/miracle下的文件
        try {
            File file = getResourcesFile();
            if (!file.isDirectory()) return null;
            File[] files = file.listFiles();
            if (files == null || files.length == 0) return null;
            for (File f : files) {
                String fileName = f.getName();
                // 找到要加载的文件
                if (!interfaceName.equals(fileName)) continue;
                // 加载使用方这个文件下的实现类
                BufferedReader bufferedReader = new BufferedReader(new FileReader(f));
                Set<String> clazzInstanceSet = bufferedReader.lines().collect(Collectors.toSet());
                if (clazzInstanceSet.isEmpty()) return null;
                list = (List<T>) load(clazzInstanceSet, interfaceName);
                break;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    /**
     * @description: 根据接口的class获取META-INF/miracle下对应的实现全类名
     * @author: tianquan
     * @date: 2024/10/14 下午7:26
     * @param: [clazz]
     * @return: java.util.Set<java.lang.String>
     **/
    public static Set<String> getClassName(Class<?> clazz) {
        String interfaceName = clazz.getCanonicalName();
        // 基于io流获取Resource下的META-INF/miracle下的文件
        try {
            File file = getResourcesFile();
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                if (files == null || files.length == 0) return null;
                for (File f : files) {
                    String fileName = f.getName();
                    // 找到要加载的文件
                    if (!interfaceName.equals(fileName)) continue;
                    // 加载使用方这个文件下的实现类
                    BufferedReader bufferedReader = new BufferedReader(new FileReader(f));
                    Set<String> clazzInstanceSet = bufferedReader.lines().collect(Collectors.toSet());
                    if (clazzInstanceSet.isEmpty()) return null;
                    return clazzInstanceSet;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * @description: 从clazzInstanceSet里获取实现了interfaceName接口的实现类
     * @author: tianquan
     * @date: 2024/10/14 下午7:27
     * @param: [clazzInstanceSet, interfaceName]
     * @return: java.util.List<java.lang.Object>
     **/
    private static List<Object> load(Set<String> clazzInstanceSet, String interfaceName) throws Exception {
        List<Object> list = new ArrayList<>();
        for (String clazzInstanceName : clazzInstanceSet) {
            // 准备实例化
            Class<?> aClass = MiracleUtils.getClassLoader().loadClass(clazzInstanceName);
            // 获取到类实现的接口或继承的父类
            Class<?>[] interfaces = aClass.getInterfaces();
            boolean isExist = false;
            for (Class<?> anInterface : interfaces) {
                String parentInterfaceName = anInterface.getCanonicalName();
                if (interfaceName.equals(parentInterfaceName)) {
                    isExist = true;
                    break;
                }
            }
            if (!isExist) throw new RuntimeException(clazzInstanceName + "class must implements " + interfaceName);
            // 无参构造实例化
            Constructor<?> constructor = aClass.getConstructor();
            String beanName = MiracleUtils.createBeanName(aClass);
            Object bean = constructor.newInstance();
            // 放入容器
            applicationContext.registerBean(beanName, bean);
            list.add(bean);
        }
        return list;
    }

}


